﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;

namespace Assets.Editor.BehaviorEditor.View
{
    public class NodeEditorView
    {
        private IRectControl parent;

        private Vector2 drag;
        private Vector2 dragDelta;

        private List<Node> nodes;
        private List<Connection> connections;
        private ConnectionPoint currentClickOutPoint;

        public event Action ExitAddNodeStatus;
        private bool enableEdit = true;
        
        public NodeEditorView(IRectControl parent)
        {
            this.parent = parent;
            nodes = new List<Node>();
            connections = new List<Connection>();
        }

        public void Draw()
        {
            var parentPos = parent.GetPos();

            Grid.Draw(parentPos, drag);

            DrawNodes();
            DrawConnections();

            GUI.Label(new Rect(500, 50, 100, 50), dragDelta.ToString());
        }

        public void ProccessEvent(Event e)
        {
            if (enableEdit)
            {
                ProccessNodesEvent(e);
                ProccessThisEvents(e);
            }

            DrawConnectionLine(e);
        }

        private void DrawConnections()
        {
            try
            {
                foreach (var connection in connections)
                {
                    connection.Draw();
                }
            }
            catch
            {
                //DONOTHING
            }
        }

        private void DrawNodes()
        {
            foreach (var node in nodes)
            {
                node.Draw();
            }
        }

        private void DrawConnectionLine(Event e)
        {
            if (currentClickOutPoint != null)
            {
                Vector2 startPos = currentClickOutPoint.rect.center;
                Vector2 endPos = e.mousePosition;

                Connection.DrawConnection(currentClickOutPoint, endPos);

                GUI.changed = true;
            }
        }

        private void ProccessThisEvents(Event e)
        {
            drag = Vector2.zero;

            switch (e.type)
            {
                case EventType.MouseDown:
                    if (e.button == 1)
                    {
                        if(addNodeStatus && ExitAddNodeStatus != null)
                        {
                            ExitAddNodeStatus();
                        }
                    }
                    else if (e.button == 0)
                    {
                        if (currentClickOutPoint != null)
                        {
                            currentClickOutPoint = null;
                        }
                        if (addNodeStatus)
                        {
                            OnClickAddNode(e.mousePosition);
                        }
                    }
                    break;
                case EventType.MouseDrag:
                    if (e.button == 2)
                    {
                        OnDrag(e);
                    }
                    break;
            }
        }

        private void OnDrag(Event e)
        {
            drag = e.delta;

            foreach (var node in nodes)
            {
                node.Drag(drag);
            }

            dragDelta += drag;
            GUI.changed = true;
        }

        private bool addNodeStatus;
        private string addNodeType;

        //假参数，实际应该传入BehaviorNodeData数据
        public void OnCheckedNodeMenuBtn(string nodeType)
        {
            addNodeStatus = true;
            addNodeType = nodeType;
        }
        
        private void OnClickAddNode(Vector2 mousePosition)
        {
            addNodeStatus = false;
            addNodeType = null;

            int newId = GenerateNewNodeId();
            string newTitle = GenerateNotRepeatTitle("new behavior ");

            Node node = new Node(
                mousePosition
                , InPointClick
                , OutPointClick
                , RemoveNodeClick
                , GetBrotherNodes);

            node.Id = newId;
            node.Title = newTitle;

            nodes.Add(node);

            if(ExitAddNodeStatus != null)
            {
                ExitAddNodeStatus();
            }
        }

        private List<Node> GetBrotherNodes(Node node)
        {
            if (node.InPoint == null)
            {
                return new List<Node>();
            }

            Node parentNode = null;
            Connection thisNodeConnection = null;
            foreach (var connection in connections)
            {
                if (connection.inPoint == node.InPoint)
                {
                    thisNodeConnection = connection;
                    parentNode = connection.outPoint.node;
                    break;
                }
            }
            if (parentNode == null)
            {
                return new List<Node>();
            }

            List<Node> brothers = new List<Node>();
            foreach (var connection in connections)
            {
                if (connection.outPoint == parentNode.OutPoint && connection != thisNodeConnection)
                {
                    brothers.Add(connection.inPoint.node);
                }
            }

            return brothers;
        }

        private int GenerateNewNodeId()
        {
            //TODO 生成节点ID
            return /*nodes.Max(n => n.Id) + */1;
        }

        private string GenerateNotRepeatTitle(string title)
        {
            string newStateTitle = title;

            var norenameNodes = nodes.Where(n => n.Title.Contains(newStateTitle)).ToList();

            List<int> numbs = new List<int>();
            foreach (var node in norenameNodes)
            {
                string numb = Regex.Replace(node.Title, @"[^0-9]+", "");
                if (!string.IsNullOrEmpty(numb))
                {
                    numbs.Add(int.Parse(numb));
                }
                else
                {
                    numbs.Add(0);
                }
            }

            return norenameNodes.Count > 0 ? newStateTitle + (numbs.Max() + 1) : newStateTitle;
        }

        private void RemoveNodeClick(Node node)
        {
            nodes.Remove(node);
        }

        private void OutPointClick(ConnectionPoint outpoint)
        {
            currentClickOutPoint = outpoint;
        }

        private void InPointClick(ConnectionPoint inpoint)
        {
            if (currentClickOutPoint != null)
            {
                if (inpoint.connections.Count == 0)
                {
                    Connection connection = new Connection(
                        inpoint
                        , currentClickOutPoint
                        , RemoveConnectionClick);
                    connections.Add(connection);

                    currentClickOutPoint = null;
                }
                else
                {
                    currentClickOutPoint = null;
                }
            }
        }

        private void RemoveConnectionClick(Connection connection)
        {
            connection.inPoint.connections.Remove(connection);
            connection.outPoint.connections.Remove(connection);
            connections.Remove(connection);
        }

        private void ProccessNodesEvent(Event e)
        {
            foreach (var node in nodes)
            {
                node.ProcessEvent(e);
            }
        }
    }
}
